import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:mi_mang_flutter/config/configs.dart';
import 'package:mi_mang_flutter/model/public/page_model.dart';
import 'package:mi_mang_flutter/network/error_code.dart';
import 'package:mi_mang_flutter/network/response_data.dart';
// import 'package:mi_mang_flutter/page/login/login_router.dart';
import 'package:mi_mang_flutter/utils/dialog_util.dart';
import 'package:mi_mang_flutter/widget/widget_error.dart';
import 'package:mi_mang_flutter/widget/widget_first_refresh.dart';
import 'package:mi_mang_flutter/widget/widget_no_data.dart';
import 'package:mi_mang_flutter/widget/widget_not_login.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';

/// 页面状态
enum ViewState {
  /// 页面首次正在加载
  loading,

  /// 加载完成,正常显示
  normal,

  /// 加载完成,空数据
  empty,

  /// 发生异常
  error,

  /// 未登录
  unauthorized,
}

/// view页面数据状态动态快照
abstract class ViewModel<T> with ChangeNotifier {
  static final Logger _log = Logger('ViewModel');

  ViewModel({Key? key, this.context});

  BuildContext? context;

  bool _disposed = false;

  // 是否是首次请求加载
  bool _isFirstLoad = true;

  // 当前view状态
  ViewState? _state;

  // 加载的数据
  T? _data;

  /// 在您不需要异步加载数据时,提供本地初始化数据
  T Function()? get local => null;

  // 数据初始化api, 主请求
  Future<T> Function()? get future => null;

  // 视图发生的错误
  Object? _error;

  /// 视图是否有数据
  bool get hasData => _data != null;

  /// 视图是否加载发生错误
  bool get hasError => _error != null;

  /// 是否是首次请求加载
  bool get isFirstLoad => _isFirstLoad;

  /// 数据实体
  T? get data => this._data;

  /// 当前view状态
  ViewState? get state => this._state;

  /// 视图发生的错误
  Object? get error => this._error;

  /// 获取可显示错误信息
  String? get errMsg => error != null
      ? (error is ResponseData
          ? (error as ResponseData).msg ?? null
          : error.toString())
      : null;

  /// 数据是否为空数据
  bool get isEmpty => data == null;

  /// 判断是否是未登录异常
  bool isNotLoginError(Object err) {
    return err is ResponseData && ErrorCode.NETWORK_LOGOUT.code == err.code;
  }

  /// 判断是否是网络异常
  bool isNetworkError(Object? err) {
    return err != null &&
        err is ResponseData &&
        (ErrorCode.NETWORK_ERROR.code == err.code ||
            ErrorCode.NETWORK_TIMEOUT.code == err.code ||
            ErrorCode.NETWORK_CONNECT_ERROR.code == err.code);
  }

  /// 设置数据
  void setData(T data) {
    if (this._data != data) {
      this._data = data;
      setState(ViewState.normal);
    }
  }

  /// 设置错误
  void setError(Object error) {
    this._error = error;
    setState(ViewState.error);
  }

  /// 设置空视图
  void setEmpty() {
    setState(ViewState.empty);
  }

  /// 设置视图状态
  void setState(ViewState state) {
    //if (this._state != state) {
    // this._state = state;
    // notifyListeners();
    //}
    if (this._state == ViewState.loading) {
      this._state = state;
      Timer(Duration(milliseconds: 300), () {
        notifyListeners();
      });
    } else {
      this._state = state;
      notifyListeners();
    }
  }

  /// 初始执行api, 初始化数据
  void init() async {
    T res = await _wrapFuture();
    if (res == null) {
      //if (isFirstLoad) {
      setEmpty();
      //}
    } else {
      setData(res);
    }
  }

  /// 包裹future处理一些公共问题, 比如api请求发生错误,未登录
  Future<T> _wrapFuture() async {
    try {
      T res;
      // 如果future为null或者future不是Future而是本地数据
      // 那么直接进入normal状态, 不加载loading动画
      // 设置初始数据为initData
      if (future == null || future is! Future<T> Function()) {
        assert(local != null);
        // 本地获取结果
        res = local!();
      } else {
        // 设置页面处于加载状态
        if (isFirstLoad) {
          setState(ViewState.loading);
        }
        // api获取结果
        res = await future!();
      }
      // 如果没有报错, 重置当次错误信息
      // 防止finally中无法设置首次加载`_isFirstLoad`为false
      this._error = null;
      return res;
    } catch (err, errStack) {
      _handlerError(err, errStack);
      // 将api异常重新抛出,防止掩盖异常,产生其他异常
      rethrow;
    } finally {
      // 将页面设置为处于非首次加载
      if (isFirstLoad && !hasError) {
        _isFirstLoad = false;
      }
    }
  }

  /// 处理错误
  void _handlerError(err, errStack) {
    _log.severe(err.toString(), err, errStack);
    // 如果是未登录, 则设置为初次登录,同时更新为跳转登录页
    this._error = err;
    if (isNotLoginError(err)) {
      this._isFirstLoad = true;
      setState(ViewState.unauthorized);
    } else {
      // 如果是其他异常, 为首次加载时更新为错误页, 如果不是首次加载只赋值异常
      if (isFirstLoad) {
        setState(ViewState.error);
      }
    }
  }

  /// 用于包裹需要登录的操作
  /// 当前页面不需要登录, 但是该操作需要登录
  /// 将该方法包裹起来, 自动弹出登录跳转框, 登录完成重新执行前面未完成的动作
  void wrapLoginDialog(Future<void> Function() todo) async {
    try {
      await todo();
    } catch (err, errStack) {
      _log.severe(err.toString(), err, errStack);
      if (isNotLoginError(err)) {
        DialogUtil.showDialogMsg(
          context,
          msg: "还未登录,前往登录?",
          onPressed: () {
            // NavigatorUtils.pushResult(context, LoginRouter.loginPage,
            //     (isLoginSuccess) {
            //   if (true == isLoginSuccess) {
            //     wrapLoginDialog(todo);
            //   }
            // });
          },
        );
      }
    }
  }

  @override
  void notifyListeners() {
    if (!_disposed) {
      super.notifyListeners();
    }
  }

  void setContext(BuildContext context) {
    if (this.context == null) {
      this.context = context;
    }
  }

  @override
  void dispose() {
    _disposed = true;
    if (Configs.DEBUG) {
      print("ViewModelProvider销毁");
    }
    super.dispose();
  }

  @override
  String toString() => '$runtimeType($state, $data, $error)';

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    if (other is! ViewModel<T>) return false;
    final ViewModel<T> typedOther = other;
    return state == typedOther.state &&
        data == typedOther.data &&
        error == typedOther.error;
  }

  @override
  int get hashCode => Object.hash(state, data, error);
}

/// 列表页模型
abstract class ListViewModel<T extends ResponseData<PageModel<S>>, S>
    extends ViewModel<T> {
  // 当前页码
  int _pageNumber = 1;

  // 是否有更多数据
  bool _isLoadMore = true;

  ListViewModel({Key? key, BuildContext? context}) : super();

  /// 当前页面
  int get pageNumber => _pageNumber;

  /// 是否有更多数据
  bool get isLoadMore => _isLoadMore;

  /// 数据列表对象
  List<S>? get list => data?.data?.records;

  /// 列表当前数据条数
  int get count => list?.length ?? 0;

  /// 数据是否为空数据
  @override
  bool get isEmpty => list == null || list!.isEmpty;

  /// 重写[]操作符
  dynamic operator [](int index) => list == null ? null : list![index];

  Future<T> _() async {
    T res = await _wrapFuture();
    PageModel<S> page = res.data!;
    // 判断是否有下一页(当前页码 * 每页行数 < 总行数)
    _isLoadMore = (page.current! * page.size!) < page.total!;
    return res;
  }

  void _refresh() async {
    _pageNumber = 1;
    T res = await _();
    this._data = res;
    if (list == null || list!.isEmpty) {
      setState(ViewState.empty);
    } else {
      setState(ViewState.normal);
    }
  }

  void _load() async {
    if (isLoadMore) {
      _pageNumber++;
      T res = await _();
      PageModel<S>? page = res.data;
      List<S> newList = page?.records ?? [];
      if (newList.isNotEmpty) {
        list!.addAll(newList);
        notifyListeners();
      }
    }
  }

  /// 列表重写数据数据初始化方法, 判断列表是否展示空数据视图不一样
  @override
  void init() async {
    _refresh();
  }

  /// 下拉刷新
  /// 这里在页面使用的时候有5种写法:
  ///  onRefresh: () async {model.onRefresh();},
  ///  onRefresh: () {return model.onRefresh();},
  ///  onRefresh: () => model.onRefresh(),
  ///  onRefresh: () async => model.onRefresh(),
  ///  onRefresh: model.onRefresh,
  ///
  /// 推荐使用最后一种写法
  Future<void> onRefresh() async {
    return _refresh();
  }

  /// 上拉加载更多
  Future<void> onLoad() async {
    return _load();
  }
}

/// ViewModel作用域
enum ViewModelScope {
  /// 当前页面(默认)
  page,

  /// 全局
  application,
}

/// view builder
typedef ViewWidgetBuilder<T extends ViewModel<S>, S> = Widget Function(
    BuildContext context, T model);

/// view组件
class ViewWidget<T extends ViewModel<S>, S> extends StatefulWidget {
  const ViewWidget({
    Key? key,
    this.model,
    this.modelScope = ViewModelScope.page,
    required this.builder,
    this.loadingBuilder,
    this.errorBuilder,
    this.emptyBuilder,
    this.unauthorizedBuilder,
    this.embeddedEmpty = false,
    this.showLoadingState = true,
    this.child,
  })  : assert(modelScope == ViewModelScope.page ? model != null : true),
        super(key: key);

  /// 视图构建器
  final Widget Function(BuildContext context, T value, Widget? child) builder;

  /// 子部件
  final Widget? child;

  /// 正在加载视图构建器
  final ViewWidgetBuilder<T, S>? loadingBuilder;

  /// 错误视图构建器
  final ViewWidgetBuilder<T, S>? errorBuilder;

  /// 空数据视图构建器
  final ViewWidgetBuilder<T, S>? emptyBuilder;

  /// 空数据视图是否在`builder`自行构建
  /// 针对部分页面需要空数据视图可能需要包含其他页面组件
  final bool embeddedEmpty;

  /// 是否需要loadingViewState过渡动画
  final bool showLoadingState;

  /// 未登录视图构建器
  final ViewWidgetBuilder<T, S>? unauthorizedBuilder;

  /// 页面数据模型
  final T? model;

  /// model作用域
  final ViewModelScope modelScope;

  @override
  State<ViewWidget<T, S>> createState() => _ViewWidgetState<T, S>();
}

/// State for [ViewWidget].
class _ViewWidgetState<T extends ViewModel<S>, S>
    extends State<ViewWidget<T, S>> {
  @override
  void initState() {
    super.initState();
    T? _model = widget.model;
    // 如果model为null, 从全局或上层获取
    if (widget.modelScope == ViewModelScope.application || _model == null) {
      _model = Provider.of<T>(context, listen: false);
      // 单次Frame绘制回调(addPostFrameCallback)
      WidgetsBinding.instance.addPostFrameCallback((_) {
        _model!.init();
      });
    } else {
      _model.init();
    }
  }

  @override
  Widget build(BuildContext context) {
    if (widget.modelScope == ViewModelScope.page) {
      return ChangeNotifierProvider<T?>.value(
        value: widget.model,
        child: _consumerBuild(),
      );
    }
    return _consumerBuild();
  }

  Widget _consumerBuild() {
    return Consumer<T>(
      builder: (context, model, child) {
        switch (model.state) {
          case ViewState.loading:
            // 如果不显示过渡动画
            if (false == widget.showLoadingState) {
              return widget.builder(context, model, child);
            }
            return widget.loadingBuilder != null
                ? widget.loadingBuilder!(context, model)
                : WidgetFirstRefresh();
          case ViewState.error:
            return widget.errorBuilder != null
                ? widget.errorBuilder!(context, model)
                : WidgetError(
                    onPressed: model.init,
                    errMsg: model.errMsg,
                    errTips: model.isNetworkError(model.error)
                        ? '请检查手机是否成功连接上网络'
                        : null,
                  );
          case ViewState.empty:
            // 如果是内嵌空数据视图
            if (widget.embeddedEmpty) {
              return widget.builder(context, model, child);
            }
            return widget.emptyBuilder != null
                ? widget.emptyBuilder!(context, model)
                : WidgetNoData();
          case ViewState.unauthorized:
            return widget.unauthorizedBuilder != null
                ? widget.unauthorizedBuilder!(context, model)
                : WidgetNotLogin(
                    onPressed: () {
                      // NavigatorUtils.push(
                      //   context,
                      //   LoginRouter.loginPage,
                      // );
                    },
                    init: () {
                      // 登录状态变化之后, 重新执行初始化方法
                      SchedulerBinding.instance.addPostFrameCallback((_) {
                        model.init();
                      });
                    },
                  );
          case ViewState.normal:
            return widget.builder(context, model, child);
          default:
        }
        return widget.builder(context, model, child);
      },
      child: widget.child,
    );
  }

//  @override
//  Widget build(BuildContext context) => widget.builder(context, _viewModel);

  @override
  void dispose() {
    super.dispose();
    // if (widget.model != null) widget.model.dispose();
    if (Configs.DEBUG) {
      print("View销毁");
    }
  }
}

/// view builder2
typedef ViewWidgetBuilder2<T1 extends ViewModel<S1>, T2 extends ViewModel<S2>,
        S1, S2>
    = Widget Function(BuildContext context, T1 model1, T2 model2);

/// 多数据源view组件
class ViewWidget2<T1 extends ViewModel<S1>, T2 extends ViewModel<S2>, S1, S2>
    extends StatefulWidget {
  const ViewWidget2({
    Key? key,
    this.model1,
    this.model2,
    this.modelScope = ViewModelScope.page,
    required this.builder,
    this.loadingBuilder,
    this.errorBuilder,
    this.emptyBuilder,
    this.unauthorizedBuilder,
    this.embeddedEmpty = false,
    this.showLoadingState = true,
    this.child,
  }) : super(key: key);

  final Widget Function(
      BuildContext context, T1 value1, T2 value2, Widget? child) builder;

  final ViewWidgetBuilder2<T1, T2, S1, S2>? loadingBuilder;
  final ViewWidgetBuilder2<T1, T2, S1, S2>? errorBuilder;
  final ViewWidgetBuilder2<T1, T2, S1, S2>? emptyBuilder;
  final ViewWidgetBuilder2<T1, T2, S1, S2>? unauthorizedBuilder;

  final Widget? child;

  final bool embeddedEmpty;

  /// 是否需要loadingViewState过渡动画
  final bool showLoadingState;

  /// 主数据模型
  final T1? model1;

  final T2? model2;

  /// model作用域
  final ViewModelScope modelScope;

  @override
  State<ViewWidget2<T1, T2, S1, S2>> createState() =>
      _ViewWidgetState2<T1, T2, S1, S2>();
}

/// State for [ViewWidget2].
class _ViewWidgetState2<T1 extends ViewModel<S1>, T2 extends ViewModel<S2>, S1,
    S2> extends State<ViewWidget2<T1, T2, S1, S2>> {
  @override
  void initState() {
    super.initState();
    T1? _model1 = widget.model1;
    T2? _model2 = widget.model2;
    // 如果model为null, 从全局或上层获取
    if (_model1 == null) {
      _model1 = Provider.of<T1>(context, listen: false);
      WidgetsBinding.instance.addPostFrameCallback((_) {
        _model1!.init();
      });
    } else {
      _model1.init();
    }
    if (_model2 == null) {
      _model2 = Provider.of<T2>(context, listen: false);
      WidgetsBinding.instance.addPostFrameCallback((_) {
        _model2!.init();
      });
    } else {
      _model2.init();
    }
  }

  @override
  Widget build(BuildContext context) {
    if (widget.modelScope == ViewModelScope.page) {
      return MultiProvider(
        providers: [
          ChangeNotifierProvider<T1?>.value(
            value: widget.model1,
          ),
          ChangeNotifierProvider<T2?>.value(
            value: widget.model2,
          )
        ],
        child: _consumerBuild(),
      );
    }
    return _consumerBuild();
  }

  Widget _consumerBuild() {
    return Consumer2<T1, T2>(
      builder: (context, model1, model2, child) {
        if (model1.state == ViewState.error ||
            model2.state == ViewState.error) {
          return widget.errorBuilder != null
              ? widget.errorBuilder!(context, model1, model2)
              : WidgetError(
                  onPressed: () {
                    model1.init();
                    model2.init();
                  },
                  errMsg: model1.errMsg ?? model2.errMsg,
                  errTips: model1.isNetworkError(model1.error ?? model2.error)
                      ? '请检查手机是否成功连接上网络'
                      : null,
                );
        }
        if (model1.state == ViewState.unauthorized ||
            model2.state == ViewState.unauthorized) {
          return widget.unauthorizedBuilder != null
              ? widget.unauthorizedBuilder!(context, model1, model2)
              : WidgetNotLogin(
                  onPressed: () {
                    // NavigatorUtils.push(
                    //   context,
                    //   LoginRouter.loginPage,
                    // );
                  },
                  init: () {
                    SchedulerBinding.instance.addPostFrameCallback((_) {
                      model1.init();
                      model2.init();
                    });
                  },
                );
        }
        if (model1.state == ViewState.loading ||
            model2.state == ViewState.loading) {
          // 如果不显示过渡动画
          if (false == widget.showLoadingState) {
            return widget.builder(context, model1, model2, child);
          }
          return widget.loadingBuilder != null
              ? widget.loadingBuilder!(context, model1, model2)
              : WidgetFirstRefresh();
        }
        if (model1.state == ViewState.empty) {
          if (widget.embeddedEmpty) {
            return widget.builder(context, model1, model2, child);
          }
          return widget.emptyBuilder != null
              ? widget.emptyBuilder!(context, model1, model2)
              : WidgetNoData();
        }
        return widget.builder(context, model1, model2, child);
      },
      child: widget.child,
    );
  }

  @override
  void dispose() {
    if (Configs.DEBUG) {
      print("ViewModel2销毁");
    }
    super.dispose();
  }
}
